/* //device/system/broncho-ril/reference-ril.c
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include <telephony/ril.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <alloca.h>
#include "telephony/ril_cdma_sms.h"
#include "atchannel.h"
#include "at_tok.h"
#include "ril_util.h"
#include <getopt.h>
#include "broncho-ril.h"

#define LOG_TAG "RIL"
#include "broncho_log.h"


static void requestCdmaDeleteSmsOnRuim(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	char * cmd = NULL;

	asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
	if(ril_command_exec_for_result(thiz, cmd))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	} 
	else 
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	free (cmd);

	return;
}

static void requestCdmaSmsAcknowledge(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	/*TODO: ack succss or failure*/
	
	if(ril_command_exec_for_result(thiz, "AT+CNMA"))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}


	return;
}

static int putTeleserviceId(unsigned char* pdu, int teleserviceId)
{
	pdu[0] = 0;
	pdu[1] = 2;
	pdu[2] = ((teleserviceId >> 8) & 0xFF);
	pdu[3] = (teleserviceId & 0xFF);

	return 4;
}

static int putServiceCategory(unsigned char* pdu, int serviceCategory)
{
	pdu[0] = 1;
	pdu[1] = 2; 
	pdu[2] = ((serviceCategory >> 8) & 0xFF);
	pdu[3] = (serviceCategory & 0xFF);

	return 4;
}

static int putCdmaAddress(unsigned char* pdu, RIL_CDMA_SMS_Address* addr, int fieldId)
{
	int startBit = 0;
	int i = 0;
	int fieldLen = 0;

	//field id and length
	putuint8(pdu, startBit, 8, fieldId);
	startBit += 16;

	//BCD code
	putuint8(pdu, startBit, 1, 0);
	putuint8(pdu, startBit, 1, 0);
	startBit += 2;

	//num field count
	putuint8(pdu, startBit, 8, addr->number_of_digits);
	startBit += 8;

	//number
	if(addr->digit_mode == 0)
	{
		for(i = 0; i < addr->number_of_digits; i++)
		{
			putuint8(pdu, startBit, 4, addr->digits[i]);
			startBit += 4;
		}
	}
	else
	{
		for(i = 0; i < addr->number_of_digits; i++)
		{
			putuint8(pdu, startBit, 4, charToBcd(addr->digits[i]));
			startBit += 4;
		}
	}
	fieldLen = (startBit + 7) / 8;
	if((startBit % 8) != 0)
	{
		putuint8(pdu, startBit, (8 - startBit%8) ,0);
	}
	putuint8(pdu, 8, 8, fieldLen - 2);

	return fieldLen;
}

static void parseAddress(RIL_CDMA_SMS_Address* addr, unsigned char* pdu)
{
	int startBit = 16;
	int numberFileds = 0;
	unsigned char byteVal = 0;
	int i = 0;
	int size = 4;

	addr->digit_mode = getuint8(pdu, startBit, 1);
	startBit++;
	addr->number_mode = getuint8(pdu, startBit, 1);
	startBit++;

	if(addr->digit_mode == 1)
	{
		if(addr->number_mode == 1)
		{
			startBit += 3;
		}
		else
		{
			startBit += 7;
		}
		size = 8;
	}
	else
	{
		size = 4;
	}
	
	numberFileds = getuint8(pdu, startBit, 8);
	startBit += 8;
	if(addr->digit_mode == 0)
	{
		for(i = 0; i < numberFileds; i++)
		{
			byteVal = getuint8(pdu, startBit, size);
			startBit += size;
			addr->digits[i] = byteVal;
		}
	}
	else
	{
		for(i = 0; i < numberFileds; i++)
		{
			byteVal = getuint8(pdu, startBit, size);
			startBit += size;
			addr->digits[i] = byteVal;
		}
	}
	addr->number_of_digits = numberFileds;

	return;
}

static void getCdmaMessageFromPdu(RIL_CDMA_SMS_Message* message, unsigned char* pdu, int pdu_len)
{
	int offset = 1;
	
	while(offset < pdu_len)
	{
		switch(pdu[offset])
		{
		case 0:
			message->uTeleserviceID = (pdu[offset + 2] << 8 )+ pdu[offset + 3];
			break;

		case 1:
			message->bIsServicePresent = 1;
			message->uServicecategory = (pdu[offset + 2] << 8 )+ pdu[offset + 3];
			break;

		case 2:
			parseAddress(&message->sAddress, pdu + offset);
			break;

		case 8:
			message->uBearerDataLen = pdu[offset + 1];
			memcpy(message->aBearerData, pdu + offset + 2, message->uBearerDataLen);
			break;

		default:
			break;
		}
		offset = offset + pdu[offset + 1] + 2;
	}

	return;
}

static char* genCdmsMessagePdu(RIL_CDMA_SMS_Message* message)
{
	int offset = 0;
	int addrLenOffset = 0;
	char* pduText = 0;
	unsigned char* pdu = calloc(1, message->uBearerDataLen + message->sAddress.number_of_digits / 2 + 20);

	/*point to point message*/
	pdu[offset++] = 0;
	
	/*teleserviceId*/
	offset += putTeleserviceId(pdu + offset, message->uTeleserviceID);
	
	/*service category*/
	if(message->bIsServicePresent)
	{
		offset += putServiceCategory(pdu + offset, message->uServicecategory);
	}

	/*destination address*/
	offset += putCdmaAddress(pdu + offset, &message->sAddress, 4);
	
	/*bearer data*/	
	pdu[offset++] = 8;
	pdu[offset++] = message->uBearerDataLen;
	memcpy(pdu + offset, message->aBearerData, message->uBearerDataLen);
	offset += message->uBearerDataLen;

	pduText = hexToString(pdu, offset);
	free(pdu);

	return pduText;
}

static void requestCdmaWriteSmsToRuim(RIL* thiz, void* data, size_t datalen, RIL_Token t)
{
	RIL_CDMA_SMS_Message* message = &(((RIL_CDMA_SMS_WriteArgs*)data)->message);
	RIL_CDMA_SMS_Address* addr = &message->sAddress;
	char* pduText = genCdmsMessagePdu(message);
	int err;
    char *cmd1 = NULL;
    RIL_SMS_Response response;
    ATResponse *p_response = NULL;
	char destAddr[RIL_CDMA_SMS_ADDRESS_MAX + 1];
	int i = 0;

	if(addr->digit_mode == 0)
	{
		for(i = 0; i < addr->number_of_digits; i++)
		{
			destAddr[i] = bcdToChar(addr->digits[i]);
		}
		destAddr[addr->number_of_digits] = '\0';
	}
	else
	{
		strcpy(destAddr, (char*)addr->digits);
	}
    asprintf(&cmd1, "AT^HCMGW=%s", destAddr);
    if ((err = ril_send_command_sms(thiz, cmd1, pduText, "^HCMGW:", &p_response)) >= 0 
		&& p_response->success != 0)
	{
	    memset(&response, 0, sizeof(response));
		at_line_scanf_int(p_response->p_intermediates->line, &response.messageRef);

	    RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &response, sizeof(response));
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	at_response_free(p_response);
	free(cmd1);
	free(pduText);

	return;
}

static void requestCdmaSendSms(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	RIL_CDMA_SMS_Message* message = (RIL_CDMA_SMS_Message*)data;
	RIL_CDMA_SMS_Address* addr = &message->sAddress;
	char* pduText = genCdmsMessagePdu(message);
	int err;
    char *cmd1 = NULL;
    RIL_SMS_Response response;
    ATResponse *p_response = NULL;
	char destAddr[RIL_CDMA_SMS_ADDRESS_MAX + 1];
	int i = 0;

	memset(&response, 0, sizeof(RIL_SMS_Response));
	if(addr->digit_mode == 0)
	{
		for(i = 0; i < addr->number_of_digits; i++)
		{
			destAddr[i] = bcdToChar(addr->digits[i]);
		}
		destAddr[addr->number_of_digits] = '\0';
	}
	else
	{
		strcpy(destAddr, (char*)addr->digits);
	}

    asprintf(&cmd1, "AT^HCMGS=\"%s\"", destAddr);;
    if ((err = ril_send_command_sms(thiz, cmd1, pduText, "^HCMGSS:", &p_response)) >= 0 
		&& p_response->success != 0)
	{
	    memset(&response, 0, sizeof(response));
		at_line_scanf_int(p_response->p_intermediates->line, &response.messageRef);

	    RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &response, sizeof(response));
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	at_response_free(p_response);
	free(cmd1);
	free(pduText);

	return;
}

static void ril_dump_message(RIL_CDMA_SMS_Message* message)
{
	int i = 0;
	char* pduText = NULL;
	
	ALOGD("**** RIL SHORT MESSAGE START ****");
	ALOGD("uTeleserviceID=%d\n", message->uTeleserviceID);
	ALOGD("bIsServicePresent=%d, uServicecategory=%d\n", message->bIsServicePresent, message->uServicecategory);
	ALOGD("digit_mode=%d, number_mode=%d, number_type=%d, number_plan=%d\n", message->sAddress.digit_mode, message->sAddress.number_mode, message->sAddress.number_type, message->sAddress.number_plan);

	for(i = 0; i < message->sAddress.number_of_digits; i++)
	{
		ALOGD("addr: %c\n", bcdToChar(message->sAddress.digits[i]));
	}
	pduText = hexToString(message->aBearerData, message->uBearerDataLen);
	ALOGD("BearerData=%s\n", pduText);
	ALOGD("**** RIL SHORT MESSAGE END ****");

	free(pduText);
	

	return;
}

static void onUnsolicited_HCMTPDU(RIL* thiz, const char* s)
{
	RIL_CDMA_SMS_Message message;
	char* dump_str = strdup(s);
	char* pduText = NULL;
	int len = 0;
	
	memset(&message, 0, sizeof(RIL_CDMA_SMS_Message));
	if(at_line_scanf_int_string(dump_str, &len, &pduText))
	{
		unsigned char* pdu = StringToHex((unsigned char*)pduText, strlen(pduText));
		getCdmaMessageFromPdu(&message, pdu, strlen(pduText) / 2);
		ril_dump_message(&message);
		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_RESPONSE_CDMA_NEW_SMS,
            &message, sizeof(message));
		free(pdu);
	}
	free(dump_str);

	return;
}

int RIL_initialize_sms (RIL* thiz)
{
	ril_send_command(thiz, "AT+CMGF=0", NULL);

	/*TODO: think-will bug. not support pdu*/
	//ril_send_command(thiz, "AT+CPMS=\"SM\",\"SM\",\"SM\"", NULL);

	ril_command_exec_full_for_result(thiz, "AT+CNMI=1,2,2,1,0", 20000);

	return 1;
}

int RIL_onUnsolicited_sms (RIL* thiz, const char* s, const char* sms_pdu)
{
	int ret = 1;

	if (strStartsWith(s, "^HCMTPDU:")) 
	{
		onUnsolicited_HCMTPDU(thiz, s);
	} 
	else if (strStartsWith(s, "+CDS:")) 
	{
        RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
            sms_pdu, strlen(sms_pdu));
	}
	else if(strStartsWith(s, "+CBM:"))
	{
		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
			sms_pdu, strlen(sms_pdu));
	}
	else if(strStartsWith(s, "^SMMEMFULL:"))
	{
		char* mem = NULL;
		if(at_line_scanf_string((char*)s, &mem) && strcmp(mem, "SM") == 0)
		{
			RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_SIM_SMS_STORAGE_FULL, NULL, 0);
		}
	}
	else 
	{
		ret = 0;
	}

	return ret;
}

int RIL_onRequest_sms (RIL* thiz, int request, void *data, size_t datalen, RIL_Token t)
{
	switch (request)
	{
	case RIL_REQUEST_SEND_SMS:
	case RIL_REQUEST_SMS_ACKNOWLEDGE:
	case RIL_REQUEST_DELETE_SMS_ON_SIM:
	case RIL_REQUEST_WRITE_SMS_TO_SIM:
	case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
	case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
	case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
	case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
		/*not use in cdma*/
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;

	case RIL_REQUEST_GET_SMSC_ADDRESS:
	case RIL_REQUEST_SET_SMSC_ADDRESS:
		/*may be cdma not support*/
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;

	case RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY:
		/*not used in framework*/
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;

	case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS:
		/*TODO: */
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;

	case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE:
		requestCdmaSmsAcknowledge(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_CDMA_SEND_SMS:
		requestCdmaSendSms(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG:
	case RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG:
	case RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION:
		/*TODO: not support now*/
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;

	case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM:
		requestCdmaWriteSmsToRuim(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM:
		requestCdmaDeleteSmsOnRuim(thiz, data, datalen, t);
		break;
	
	default:
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;
	}

	return 1;
}

